﻿using System.Linq;

namespace GlobalStringFormatter
{
    /// <summary>
    /// Represents a global string with conditionalized formatted output.
    /// </summary>
    /// <typeparam name="TType">Any class-type. Usually a value-type like double, int, or string.</typeparam>
    /// <typeparam name="TFormatter">Any type used to denote a type of formatting. Used solely for your book-keeping needs.</typeparam>
    public class GString<TFormatter, TType> : IGString<TFormatter, TType>
    {
        #region Properties

        private FormatterSystem<TType> _formatters;

        /// <summary>
        /// Any class-object. Usually a value-type like double, int, or string.
        /// </summary>
        public TType Value { get; set; }

        /// <summary>
        /// The FormatterSystem attached to this global string.
        /// </summary>
        public FormatterSystem<TType> Formatters
        {
            get { return _formatters; }
            set { _formatters = value; }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Copy constructor. Creates a new GString with a new FormatterSystem
        /// </summary>
        /// <param name="gString">The GString to be copied.</param>
        public GString(GString<TFormatter, TType> gString)
        {
            _formatters = new FormatterSystem<TType>(gString.Formatters);
            Value = gString.Value;
        }

        /// <summary>
        /// Empty constructor. FormatterSystem contains no predicates. Value set
        /// to the default for its class.
        /// </summary>
        public GString()
        {
            _formatters = new FormatterSystem<TType>();
            Value = default(TType);
        }

        /// <summary>
        /// Constructor for a GString with a value.
        /// </summary>
        /// <param name="value">The raw value used to drive the formatted output.</param>
        public GString(TType value)
        {
            _formatters = new FormatterSystem<TType>();
            Value = value;
        }

        /// <summary>
        /// Constructor for a GString with a value and a FormatterSystem.
        /// </summary>
        /// <param name="value">The raw value used to drive the formatted output.</param>
        /// <param name="formatterSystem"></param>
        public GString(TType value, FormatterSystem<TType> formatterSystem)
        {
            _formatters = formatterSystem;
            Value = value;
        }

        #endregion

        #region Overrides

        /// <summary>
        /// Outputs the conditionalized formatted string representation of the raw value.
        /// </summary>
        /// <returns>Formatted string.</returns>
        public override string ToString()
        {
            var formatters = _formatters.GetFormatters();

            foreach (var formatter in formatters.Where(formatter => formatter.PredicateFunction(Value)))
                return formatter.FormatFunction(Value);

            return _formatters.Default(Value);
        }

        #endregion
    }
}
